#include<linux/module.h>
#include<linux/cdev.h>
#include<linux/device.h>
#include<linux/uaccess.h>

#define DEVICE_NAME "my_test_device"
#define CLASS_NAME "my_test_class"

static dev_t dev_num;
static struct cdev c_dev;
static struct device *dev;
static struct class *cl;

static int dev_open(struct inode *inode,struct file *file){
	printk("%s is opened\n",DEVICE_NAME);
	return 0;
}

static int dev_close(struct inode *inode,struct file *file){
	printk("%s is closed\n",DEVICE_NAME);
	return 0;
}

static ssize_t dev_write(struct file *file,const char __user *buf,size_t len,loff_t *offset){
	char *kernel_buf;

	kernel_buf=kmalloc(len+1,GFP_KERNEL);
	if(!kernel_buf){
		return -ENOMEM;
	}

	if(copy_from_user(kernel_buf,buf,len)){
		kfree(kernel_buf);
		return -EFAULT;
	}
	kernel_buf[len]='\0';

	printk("from user buf write %s",kernel_buf);
	kfree(kernel_buf);

	return len;
}

static ssize_t dev_read(struct file *file,char __user *buf,size_t len,loff_t *offset){
	printk("%s is read\n");
	return 0;
}

static struct file_operations fops={
	.owner=THIS_MODULE,
	.open=dev_open,
	.release=dev_close,
	.write=dev_write,
	.read=dev_read,
};

static int __init dev_init(void){
	int ret;

	ret=alloc_chrdev_region(&dev_num,0,1,DEVICE_NAME);
	if(ret<0){
		printk(KERN_ERR "Failed to alloced device number\n");
		return ret;
	}

	cl = class_create(THIS_MODULE,CLASS_NAME);
	if(IS_ERR(cl)){
		unregister_chrdev_region(dev_num,1);
		return PTR_ERR(cl);
	}

	dev=device_create(cl,NULL,dev_num,NULL,DEVICE_NAME);
	if(IS_ERR(dev)){
		class_destroy(cl);
		unregister_chrdev_region(dev_num,1);
		return PTR_ERR(dev);
	}

	cdev_init(&c_dev,&fops);
	ret=cdev_add(&c_dev,dev_num,1);
	if(ret<0){
		device_destroy(cl,dev_num);
		class_destroy(cl);
		unregister_chrdev_region(dev_num,1);
		return ret;
	}

	printk("my test device is inited\n");
	return 0;
}

static void __exit dev_exit(void){
	cdev_del(&c_dev);
	device_destroy(cl,dev_num);
	class_destroy(cl);
	unregister_chrdev_region(dev_num,1);
}

module_init(dev_init);
module_exit(dev_exit);

MODULE_LICENSE("GPL");
MODULE_AUTHOR("zhuzonghui <puchuchen@outlook.com>");
MODULE_DESCRIPTION("This is my test dev");
